/* Octopus PDF - A simple document viewer for Android.
   Copyright (C) 2013  Gerald Thaler

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
package de.geraldthaler.octopuspdf.memory;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;

/**
 * @author Gerald Thaler
 */
public final class DirectByteBufferPool {
    private static final int MIN_SIZE = 16;
    private static final int MAX_SIZE = 0x40000;
    
    @SuppressWarnings("unchecked")
    private final ArrayList<ByteBuffer>[] pool = new ArrayList[15];
    
    public synchronized ByteBuffer allocate(final int minCapacity) {
        for (int n = 0, c = MIN_SIZE; c <= MAX_SIZE; ++n, c <<= 1) {
            if (c >= minCapacity) {
                final ArrayList<ByteBuffer> bl = pool[n];
                if (bl != null && !bl.isEmpty())
                    return bl.remove(bl.size() - 1);
                final ByteBuffer buffer = ByteBuffer.allocateDirect(c);
                buffer.order(ByteOrder.nativeOrder());
                return buffer;
            }
        }
        throw new AssertionError(minCapacity);
    }

    public synchronized void free(final ByteBuffer buffer) {
        if (buffer == null)
            return;
        buffer.clear();
        final int capacity = buffer.capacity();
        for (int n = 0, c = MIN_SIZE; c <= MAX_SIZE; ++n, c <<= 1) {
            if (c == capacity) {
                ArrayList<ByteBuffer> bl = pool[n];
                if (bl == null) {
                    bl = new ArrayList<ByteBuffer>(1);
                    pool[n] = bl;
                }
                bl.add(buffer);
                return;
            }
        }
        throw new AssertionError(capacity);
    }
}
